﻿using System;
using System.Collections.Generic;
using System.Text;
using NAudio;
using NAudio.Wave;

namespace slCommunicator
{
    public static class DuplexAudio
    {
        public static WaveFormat wformat = new WaveFormat(Properties.Settings.Default.audio_sampleRate, 16, Properties.Settings.Default.audio_channels);
        public const NSpeex.BandMode bandmode = NSpeex.BandMode.Narrow;

        private static BufferedWaveProvider playBuffer;
        private static voiceChanger.LVoice voiceEffects;

        private static WaveOut waveOut;
        private static WaveInEvent waveIn;

        public static void Start()
        {
            voiceEffects = new voiceChanger.LVoice(wformat);
            playBuffer = new BufferedWaveProvider(wformat);
            playBuffer.DiscardOnBufferOverflow = true;
            voiceEffects.OutputAvailable += voiceEffects_OutputAvailable;

            waveIn = new WaveInEvent();
            waveIn.WaveFormat = wformat;
            waveIn.BufferMilliseconds = Properties.Settings.Default.audio_bufferMs;
            waveIn.DataAvailable += voiceEffects.DataAvailable;
            waveIn.StartRecording();

            waveOut = new WaveOut();
            waveOut.Init(playBuffer);
            waveOut.Play();

            Console.WriteLine(localization.session_audioApparatusCreated);
        }

        static void voiceEffects_OutputAvailable(object sender, WaveInEventArgs e)
        {
            if (Session.currentSession == null)
                return;
            Recorder.DataIn(e.Buffer, true);
            try
            {
                byte[] preparedAudio = AudioPrepare.PrepareToSend(e.Buffer);
                Session.currentSession.SendData(preparedAudio);
            }
            catch (Exception ex)
            {
                Console.WriteLine("voiceEffects_OutputAvailable " + ex.Message);
            }
        }

        public static void PlayEncodedEncrypted(byte[] buffer)
        {
            byte[] decAudio = AudioPrepare.PrepareReceived(buffer);

            playBuffer.AddSamples(decAudio, 0, decAudio.Length);
            Recorder.DataIn(decAudio, false);
            SessionForm.DrawWave(decAudio);
        }

        public static void Exit()
        {
            waveIn.StopRecording();
            waveOut.Stop();
        }
    }
}

public class SineWaveProvider : IWaveProvider
{
    int sample;
    private WaveFormat waveFormat;

    public float amplitude = 0.25f;
    public int freq = 1000;

    public SineWaveProvider()
        : this(8000, 1)
    {
    }

    public SineWaveProvider(int sampleRate, int channels)
    {
        SetWaveFormat(sampleRate, channels);
    }

    public void SetWaveFormat(int sampleRate, int channels)
    {
        this.waveFormat = WaveFormat.CreateIeeeFloatWaveFormat(sampleRate, channels);
    }

    public int Read(byte[] buffer, int offset, int count)
    {
        WaveBuffer waveBuffer = new WaveBuffer(buffer);

        int samplesRequired = count / 4;

        int sampleRate = WaveFormat.SampleRate;
        for (int n = 0; n < samplesRequired; n++)
        {
            waveBuffer.FloatBuffer[n + offset/4] = (float)(amplitude * Math.Sin((2 * Math.PI * sample * 1000) / freq));
            sample++;
            if (sample >= sampleRate) sample = 0;
        }

        return count;
    }

    public WaveFormat WaveFormat
    {
        get { return waveFormat; }
    }
}
